package br.com.educa.modelo.pessoa;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.PersistenceContext;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import javax.persistence.TypedQuery;
import javax.persistence.Version;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;

import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord;
import org.springframework.roo.addon.json.RooJson;
import org.springframework.roo.addon.serializable.RooSerializable;
import org.springframework.roo.addon.tostring.RooToString;
import org.springframework.transaction.annotation.Transactional;

import br.com.educa.modelo.academico.Alunos;
import br.com.educa.modelo.pessoa.enumerator.EstadoCivil;
import br.com.educa.modelo.pessoa.enumerator.Sexo;
import br.com.educa.modelo.publico.Bairro;
import br.com.educa.modelo.publico.Cidade;
import br.com.educa.modelo.publico.Pais;
import flexjson.JSONDeserializer;
import flexjson.JSONSerializer;

@Entity
@Table
@Configurable
@RooSerializable
@RooJson
@RooJavaBean
@RooToString
@RooJpaActiveRecord(finders = {"findPessoasesByNomeLike", "findPessoasesByNomeLikeisAluno", "findPessoasesByNomeLikeisAlunoCombo" })
public class Pessoas implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Version
    @Column(name = "version")
    private Integer version;

    @NotNull
    private String nome;

    @Pattern(regexp = "^([0-9]{2,3}?\\.[0-9]{3}?\\.[0-9]{3}?\\-[0-9]{2}?)$")
    private String cpf;

    @Enumerated(EnumType.STRING)
    private Sexo sexo;

    @Temporal(TemporalType.DATE)
    @DateTimeFormat(style = "M-")
    private Date nascimento;
    
    private String mae;
    
    private String pai;

    private String rgCivil;

    private String orgaoExpedidor;

    @Enumerated(EnumType.STRING)
    private EstadoCivil estadoCivil;

    @NotNull
    private String tipoCadastro;

    @ManyToOne
    @JoinColumn(referencedColumnName = "id")
    private Pais nacionalidade;

    @ManyToOne
    @JoinColumn(referencedColumnName = "id")
    private Cidade naturalidade;

    @ManyToOne
    @JoinColumn(referencedColumnName = "id")
    private Bairro bairro;

    @NotNull
    private String logradouro;

    private String complemento;

    @Column(length = 10)
    private String cep;

    @Column(length = 100)
    private String celular;

    @Column(length = 100)
    private String telefone;

    @Pattern(regexp = "^([0-9a-zA-Z]([-.\\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\\w]*[0-9a-zA-Z]\\.)+[a-zA-Z]{2,9})$", message = "Email inválido!")
    private String email;

    private String observacao;

    @Temporal(TemporalType.DATE)
    @DateTimeFormat(style = "M-")
    private Date dataCadastro;

    private Boolean ativo = true;

    private Boolean isStudent = false;
    
//    @OneToMany(cascade = CascadeType.ALL, orphanRemoval=true)
//    @JoinColumn(name = "pessoaAluno", referencedColumnName = "id", nullable = false)
//    private Set<Alunos> pessoasAlunos;

    private static final long serialVersionUID = 1L;

    @PersistenceContext
    transient EntityManager entityManager;

    @Transient
    String nomeComNomeMae;

    public String toJson() {
        return new JSONSerializer().exclude("*.class").serialize(this);
    }

    public static br.com.educa.modelo.pessoa.Pessoas fromJsonToPessoas(String json) {
        return new JSONDeserializer<Pessoas>().use(null, Pessoas.class).deserialize(json);
    }

    public static String toJsonArray(Collection<br.com.educa.modelo.pessoa.Pessoas> collection) {
        return new JSONSerializer().exclude("*.class").serialize(collection);
    }

    public static Collection<br.com.educa.modelo.pessoa.Pessoas> fromJsonArrayToPessoases(String json) {
        return new JSONDeserializer<List<Pessoas>>().use(null, ArrayList.class).use("values", Pessoas.class).deserialize(json);
    }

    public Long getId() {
        return this.id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Integer getVersion() {
        return this.version;
    }

    public void setVersion(Integer version) {
        this.version = version;
    }

    public String getNome() {
        return this.nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public String getCpf() {
        return this.cpf;
    }

    public void setCpf(String cpf) {
        this.cpf = cpf;
    }

    public Sexo getSexo() {
        return this.sexo;
    }

    public void setSexo(Sexo sexo) {
        this.sexo = sexo;
    }

    public Date getNascimento() {
        return this.nascimento;
    }

    public void setNascimento(Date nascimento) {
        this.nascimento = nascimento;
    }

    public String getRgCivil() {
        return this.rgCivil;
    }

    public void setRgCivil(String rgCivil) {
        this.rgCivil = rgCivil;
    }

    public String getOrgaoExpedidor() {
        return this.orgaoExpedidor;
    }

    public void setOrgaoExpedidor(String orgaoExpedidor) {
        this.orgaoExpedidor = orgaoExpedidor;
    }

    public EstadoCivil getEstadoCivil() {
        return this.estadoCivil;
    }

    public void setEstadoCivil(EstadoCivil estadoCivil) {
        this.estadoCivil = estadoCivil;
    }

    public String getTipoCadastro() {
        return this.tipoCadastro;
    }

    public void setTipoCadastro(String tipoCadastro) {
        this.tipoCadastro = tipoCadastro;
    }

    public Pais getNacionalidade() {
        return this.nacionalidade;
    }

    public void setNacionalidade(Pais nacionalidade) {
        this.nacionalidade = nacionalidade;
    }

    public Cidade getNaturalidade() {
        return this.naturalidade;
    }

    public void setNaturalidade(Cidade naturalidade) {
        this.naturalidade = naturalidade;
    }

    public Bairro getBairro() {
        return this.bairro;
    }

    public void setBairro(Bairro bairro) {
        this.bairro = bairro;
    }

    public String getLogradouro() {
        return this.logradouro;
    }

    public void setLogradouro(String logradouro) {
        this.logradouro = logradouro;
    }

    public String getComplemento() {
        return this.complemento;
    }

    public void setComplemento(String complemento) {
        this.complemento = complemento;
    }

    public String getCep() {
        return this.cep;
    }

    public void setCep(String cep) {
        this.cep = cep;
    }

    public String getCelular() {
        return this.celular;
    }

    public void setCelular(String celular) {
        this.celular = celular;
    }

    public String getTelefone() {
        return this.telefone;
    }

    public void setTelefone(String telefone) {
        this.telefone = telefone;
    }

    public String getEmail() {
        return this.email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getObservacao() {
        return this.observacao;
    }

    public void setObservacao(String observacao) {
        this.observacao = observacao;
    }

    public Date getDataCadastro() {
        return this.dataCadastro;
    }

    public void setDataCadastro(Date dataCadastro) {
        this.dataCadastro = dataCadastro;
    }

    public Boolean getAtivo() {
        return this.ativo;
    }

    public void setAtivo(Boolean ativo) {
        this.ativo = ativo;
    }

    public String toString() {
        return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE);
    }

    public static final EntityManager entityManager() {
        EntityManager em = new Pessoas().entityManager;
        if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
        return em;
    }

    public static long countPessoases() {
        return entityManager().createQuery("SELECT COUNT(o) FROM Pessoas o", Long.class).getSingleResult();
    }

    public static List<br.com.educa.modelo.pessoa.Pessoas> findAllPessoases() {
        return entityManager().createQuery("SELECT o FROM Pessoas o", Pessoas.class).getResultList();
    }

    public static br.com.educa.modelo.pessoa.Pessoas findPessoas(Long id) {
        if (id == null) return null;
        return entityManager().find(Pessoas.class, id);
    }

    public static List<br.com.educa.modelo.pessoa.Pessoas> findPessoasEntries(int firstResult, int maxResults) {
        return entityManager().createQuery("SELECT o FROM Pessoas o", Pessoas.class).setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
    }

    @Transactional
    public void persist() {
        if (this.entityManager == null) this.entityManager = entityManager();
        this.entityManager.persist(this);
    }

    @Transactional
    public void remove() {
        if (this.entityManager == null) this.entityManager = entityManager();
        if (this.entityManager.contains(this)) {
            this.entityManager.remove(this);
        } else {
            Pessoas attached = Pessoas.findPessoas(this.id);
            this.entityManager.remove(attached);
        }
    }

    @Transactional
    public void flush() {
        if (this.entityManager == null) this.entityManager = entityManager();
        this.entityManager.flush();
    }

    @Transactional
    public void clear() {
        if (this.entityManager == null) this.entityManager = entityManager();
        this.entityManager.clear();
    }

    @Transactional
    public br.com.educa.modelo.pessoa.Pessoas merge() {
        if (this.entityManager == null) this.entityManager = entityManager();
        Pessoas merged = this.entityManager.merge(this);
        this.entityManager.flush();
        return merged;
    }

	public Boolean getIsStudent() {
        return this.isStudent;
    }

	public void setIsStudent(Boolean isStudent) {
        this.isStudent = isStudent;
    }

	public String getNomeComNomeMae() {
        return this.nomeComNomeMae;
    }

	public void setNomeComNomeMae(String nomeComNomeMae) {
        this.nomeComNomeMae = nomeComNomeMae;
    }

	public static TypedQuery<Pessoas> findPessoasesByNomeLike(String nome) {
        if (nome == null || nome.length() == 0) throw new IllegalArgumentException("The nome argument is required");
        nome = nome.replace('*', '%');
        if (nome.charAt(0) != '%') {
            nome = "%" + nome;
        }
        if (nome.charAt(nome.length() - 1) != '%') {
            nome = nome + "%";
        }
        EntityManager em = Pessoas.entityManager();
        TypedQuery<Pessoas> q = em.createQuery("SELECT o FROM Pessoas AS o WHERE LOWER(o.nome) LIKE LOWER(:nome)", Pessoas.class);
        q.setParameter("nome", nome);
        return q;
    }
	
	public static TypedQuery<Pessoas> findPessoasesByNomeLikeisAluno(String nome) {
        if (nome == null || nome.length() == 0) throw new IllegalArgumentException("The nome argument is required");
        nome = nome.replace('*', '%');
        if (nome.charAt(0) != '%') {
            nome = "%" + nome;
        }
        if (nome.charAt(nome.length() - 1) != '%') {
            nome = nome + "%";
        }
        EntityManager em = Pessoas.entityManager();
        TypedQuery<Pessoas> q = em.createQuery("SELECT o FROM Pessoas AS o, Alunos AS a WHERE LOWER(o.nome) LIKE LOWER(:nome) AND o.isStudent = true", Pessoas.class);
        q.setParameter("nome", nome);
        return q;
    }
	
	public static TypedQuery<Pessoas> findPessoasesByNomeLikeisAlunoCombo(String nome) {
        if (nome == null || nome.length() == 0) throw new IllegalArgumentException("The nome argument is required");
        nome = nome.replace('*', '%');
        if (nome.charAt(0) != '%') {
            nome = "%" + nome;
        }
        if (nome.charAt(nome.length() - 1) != '%') {
            nome = nome + "%";
        }
        EntityManager em = Pessoas.entityManager();
        TypedQuery<Pessoas> q = em.createQuery("SELECT o FROM Pessoas AS o WHERE LOWER(o.nome) LIKE LOWER(:nome) AND o.isStudent = true", Pessoas.class);
        q.setParameter("nome", nome);
        return q;
    }

	public String getMae() {
        return this.mae;
    }

	public void setMae(String mae) {
        this.mae = mae;
    }

	public String getPai() {
        return this.pai;
    }

	public void setPai(String pai) {
        this.pai = pai;
    }
}
